package cprofilesvc

import (
	"context"
	"encoding/json"
	"github.com/go-redis/redis/v8"
	corev1 "gluenet/internal/agent/api/core/v1"
	"gluenet/internal/agent/depend"
	"gluenet/internal/agent/service/redissvc"
	"gluenet/utils/rpc/v2/define"
	"io"
	"net/http"
	"strings"
)

type CprofileRootFunction struct {
	CumTime       float64                   `json:"cumtime"`
	RootFunctions []cprofileRuntimeFunction `json:"root_functions"`
}

type cprofileRuntimeFunction struct {
	TotalInfo        runtimeFunctionTotal      `json:"total"`
	RunTimeInCaller  runtimeFunctionInCaller   `json:"runtime_in_caller"`
	SubFunctionCount int64                     `json:"sub_function_count"`
	SubFunctions     []cprofileRuntimeFunction `json:"sub_functions"`
}

type runtimeFunctionTotal struct {
	File    string  `json:"file"`
	Line    int64   `json:"line"`
	Name    string  `json:"name"`
	CumTime float64 `json:"cumtime"`
	TotTime float64 `json:"tottime"`
	NCalls  int64   `json:"ncalls"`
}

type runtimeFunctionInCaller struct {
	File    string  `json:"file"`
	Line    int64   `json:"line"`
	Name    string  `json:"name"`
	CumTime float64 `json:"cumtime"`
	TotTime float64 `json:"tottime"`
	NCalls  int64   `json:"ncalls"`
}

func (svc *Service) CprofileFlame(cprofileFlame define.CprofileFlame) corev1.CommonResp {
	var rootFunction CprofileRootFunction
	resp := make(map[string]CprofileRootFunction)
	redisClient := redis.NewClient(&redis.Options{
		Addr:     depend.Produce[*redissvc.RedisConfig]().Addr,
		Password: depend.Produce[*redissvc.RedisConfig]().Password, // no password set
		DB:       0,                                                // use
		// default DB
	})
	_, err := redisClient.Ping(context.Background()).Result()
	if err != nil {
		svc.logger.Errorf(err.Error())
		return corev1.NewCommonFailureResp(err.Error())
	}
	key := "cprofileFlame" + "#" + cprofileFlame.Guid + "#" + cprofileFlame.Pod + "*"
	keys, err := redisClient.Keys(context.Background(), key).Result()
	if err != nil {
		svc.logger.Errorf(err.Error())
		return corev1.NewCommonFailureResp(err.Error())
	}
	if len(keys) == 0 {
		svc.logger.Errorf("no key found")
		return corev1.NewCommonFailureResp("no key found")
	}
	for _, key := range keys {
		result := redisClient.Get(context.Background(), key).Val()
		err := json.Unmarshal([]byte(result), &rootFunction)
		if err != nil {
			svc.logger.Errorf(err.Error())
			return corev1.NewCommonFailureResp(err.Error())
		}
		resp[key[strings.Index(key, "#")+1:]] = rootFunction
	}
	return corev1.NewCommonSuccessRespWithData(resp)
}

func (svc *Service) CprofileFile(cprofileFile define.CprofileFile) corev1.CommonResp {
	resp, err := http.Get(cprofileFile.URL)
	if err != nil {
		svc.logger.Errorf(err.Error())
		return corev1.NewCommonFailureResp(err.Error())
	}
	defer resp.Body.Close()
	data, err := io.ReadAll(resp.Body)
	if err != nil {
		svc.logger.Errorf(err.Error())
		return corev1.NewCommonFailureResp(err.Error())
	}
	return corev1.NewCommonSuccessRespWithData(string(data))
}
